home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 19
/
Mac Magazin and MacEasy Magazine CD - Issue 19.iso
/
Musik & Kunst
/
Ear Workout 2.1
/
source code
/
ear_about_chord.cp
< prev
next >
Wrap
Text File
|
1996-01-15
|
11KB
|
311 lines
//
// current shortcomings:
// doesn't know about ledger lines, except for middle C
// note heads and accidentals don't look so great
// should allow user to set the value of spell spell_dim7_enharmonically
// as a matter of preference
// sometimes leaves notes out of staff:
// happened for F#m, drew F# and C# only !?!?
// might have to do with reinterpreting m7 <-> 6
// on very first chord, draws accidentals but then erases them later
// when it redraws the chord
// should try to spell chord so as to avoid double sharps and double-flats,
// e.g. G# dim7, not Ab dim 7
// has problems with the ADDMAJ7 item, spells it as 6:
// screwed up on writing a C#m maj 7 chord voiced as E, G#, Bx, C#(oct up)
// wrote Bx as A, wrote accidentals in funny places
// spells Ab b5 maj7 with Fx instead of G
// should have curly brace at left
//
// fixed (?):
// if a chord has 2 seconds in a row, should bring the top note back
// to the left
// spells 4 of sus 4 as #3
// chord symbols:
// should use space in some cases, e.g. "E half-dim", not "Ehalf-dim"
// should say "G", not "GM"
// If a note is offset to the right to avoid colliding with one a second
// below it, and only the higer note has an accidental, don't
// need to offset the accidental.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <OSUtils.h>
#include <QuickDraw.h>
#include <Sound.h>
#define NEED_MAC_STUFF 1
#include "Ninkasi:C++ util:generic.h"
#include "Ninkasi:C++ util:complete_window.h"
#include "ear_defines.h"
#include "ear_decl.h"
#include "ear_prototypes.h"
DEN_MOTHER_T about_chord_den_mother;
#define MAXPART 200
// highest part number in our window
extern double fabs(),sin(),cos();
void
about_chord_den_mother(complete_window *my_complete_window)
{
//--- decoder string for controls:
static char *decoder_ptr =
"\0staff,symbol,tx1,chord_no";
//--- has to begin with null so subroutines know it's not really
// a Pascal string
static char **decoder_string = &decoder_ptr;
static int first_time = 1;
static int ready_to_update,need_to_redraw,need_to_redraw_all;
static int root_letter,root_accidental;
char nifty_name[300];
int nifty_index;
GrafPtr save_graf;
need_to_redraw = 0;
need_to_redraw_all = 0;
ready_to_update = 0;
if (first_time) {
first_time = 0;
}
switch(my_complete_window->whassup) {
case complete_window_created:
need_to_redraw = 1;
need_to_redraw_all = 1;
about_chord_window_exists = 1;
break;
case complete_window_redraw:
need_to_redraw = 1;
need_to_redraw_all = 1;
ready_to_update = 1; //-- main program does begin update & sets graf port
break;
case complete_window_action:
part_number_to_nifty_label(nifty_name,&nifty_index,
*decoder_string,my_complete_window->part_number);
if (nifty_index != -999) {
if (strcmp(nifty_name,"aardvark")==0) {
}
}//--end if they hit a valid control
break;
case complete_window_erase:
first_time = 1;
return;
}
if (need_to_redraw) {
if (!ready_to_update) {
GetPort(&save_graf);
SetPort(my_complete_window->the_window);
}
if (have_previous_chord) {
//----- draw staff and chord on it ------
Rect rr,staff;
short x_mid,y_mid,x,y,staff_top,staff_bottom,x_chord,y_chord;
double h;
Handle hh;
char s[200],s2[200];
Point p;
int list_position_on_staff[MAX_CHORD_NOTES];
int i,err,note_letter,accidental,
rough_position_on_staff,position_on_staff,last_position_on_staff,
last_note_was_offset,last_note_had_accidental,offset,
last_accidental_was_offset,width_of_note,bar_line_top,
bar_line_bottom;
get_rect_by_nifty_label(my_complete_window->the_window,
"staff",1,decoder_ptr,&rr);
FillRect(&rr,&white);
h = 10.; //-- distance between lines on staff
y_mid = .5*(rr.top+rr.bottom)+.5;
x_mid = .5*(rr.left+rr.right)+.5;
staff_top = y_mid-2*h+.5;
staff_bottom = y_mid+2*h+.5;
x_chord = x_mid + 1.5 * h;
y_chord = y_mid;
// treble clef:
SetRect(&staff,rr.left,staff_top,rr.right,staff_bottom);
bar_line_top = staff_top;
draw_staff(&staff);
draw_clef("draw","g_clef",
(int) (x_mid-30),(int) y_mid,h,(void *) 0,(void *) 0);
// bass clef:
staff_top = staff_top + 6*h;
staff_bottom = staff_bottom + 6*h;
SetRect(&staff,rr.left,staff_top,rr.right,staff_bottom);
bar_line_bottom = staff_bottom;
draw_staff(&staff);
draw_clef("draw","f_clef",
(int) (x_mid-30),(int) (y_mid+6*h),h,(void *) 0,(void *) 0);
// double bar:
MoveTo((short) (rr.right-.5*h),(short) bar_line_top);
LineTo((short) (rr.right-.5*h),(short) bar_line_bottom);
MoveTo((short) (rr.right),(short) bar_line_top);
LineTo((short) (rr.right),(short) bar_line_bottom);
// single bar at left to show it's a grand staff; should
// also have curly brace
MoveTo((short) (rr.left),(short) bar_line_top);
LineTo((short) (rr.left),(short) bar_line_bottom);
sort_int_list(previous_chord,previous_n_notes);
draw_note_head("set_h",0,0,0,(void *) 0,&h);
draw_note_head("right_tangent",
(int) x_chord,(int) y,0,(void *) &p,(void *) 0);
width_of_note = 2*(p.h-x_chord);
switch(make_0_to_11(previous_root-MIDDLE_C)) {
case 0: root_letter = 0; root_accidental = 0; break; // C
case 1: root_letter = 0; root_accidental = 1; break; // C#
case 2: root_letter = 1; root_accidental = 0; break; // D
case 3: root_letter = 2; root_accidental = -1; break; // Eb
case 4: root_letter = 2; root_accidental = 0; break; // E
case 5: root_letter = 3; root_accidental = 0; break; // F
case 6: root_letter = 3; root_accidental = 1; break; // F#
case 7: root_letter = 4; root_accidental = 0; break; // G
case 8: root_letter = 5; root_accidental = -1; break; // Ab
case 9: root_letter = 5; root_accidental = 0; break; // A
case 10: root_letter = 6; root_accidental = -1; break; // Bb
case 11: root_letter = 6; root_accidental = -1; break; // B
}
last_position_on_staff = -999;
for (i=0; i<previous_n_notes; i++) {
spell_note_as_part_of_chord(&err,¬e_letter,&accidental,
previous_chord[i]-previous_root,root_letter,root_accidental,
previous_item,previous_n_items,spell_dim7_enharmonically);
if (err==0) {
rough_position_on_staff = (previous_chord[i]-(MIDDLE_C+11.))*7./12.;
//...relative to B in middle of treble clef
position_on_staff = note_letter-6;
//...relative to B in middle of treble clef
while (position_on_staff<rough_position_on_staff-3.5)
position_on_staff += 7;
while (position_on_staff>rough_position_on_staff+3.5)
position_on_staff -= 7;
list_position_on_staff[i] = position_on_staff;
y = y_chord-.5*h*position_on_staff;
if (position_on_staff<last_position_on_staff+2
&& !last_note_was_offset) {
offset = width_of_note;
last_note_was_offset = 1;
}
else {
offset = 0;
last_note_was_offset = 0;
}
x = x_chord+offset;
draw_note_head("draw",(int) x,(int) y,0,(void *) 0,(void *) 0);
if (position_on_staff == -6) {
// ledger line for middle C
MoveTo((short) (x-h),(short) y);
LineTo((short) (x+h),(short) y);
}
if (accidental!=0) {
char s[100];
FontInfo fi;
short x_acc,y_acc;
describe_accidental(s+1,accidental);
s[0] = strlen(s);
normal_text_style();
GetFontInfo(&fi);
x_acc = x_chord-h-5-StringWidth((unsigned char *) s);
if (position_on_staff<last_position_on_staff+2
&& last_note_had_accidental
&& !last_accidental_was_offset) {
x_acc = x_acc + width_of_note;
last_accidental_was_offset = 1;
}
else
last_accidental_was_offset = 0;
y_acc = y+.5*fi.ascent;
if (accidental<0) y_acc = y_acc-2;
if (accidental==2) y_acc = y_acc-1;
MoveTo(x_acc,y_acc);
DrawString((unsigned char *) s);
normal_text_style();
} //-- end if accidental
last_position_on_staff = position_on_staff;
last_note_had_accidental = (accidental!=0);
} //-- end if no error
} //-- end loop over notes
//----- chord symbol ------
{
char s1[100],s2[30],s3[100];
Handle hh;
get_item_by_nifty_label(my_complete_window->the_window,
"symbol",1,decoder_ptr,&hh);
if (VALID_HANDLE(hh)) {
describe_chord(s3,previous_n_items,previous_item);
if (strcmp(s3,"M")==0)
strcpy(s3,"");
if (strlen(s3)>=8 && strncmp(s3,"half-dim",8)==0)
sprintf(s1," %s",s3);
else
strcpy(s1,s3);
describe_accidental(s2,root_accidental);
sprintf(s+1,"%c%s%s",
"CDEFGAB"[root_letter],
s2,s1);
s[0] = strlen(s+1);
normal_text_style();
SetIText(hh,(unsigned char *) s);
normal_text_style();
}
}
//----- chord number ------
{
Handle hh;
char s[50];
int chord_no;
chord_no = nifty_chord_number(previous_chord,previous_n_notes);
//chord_no = notes_to_quick_label(previous_chord,previous_n_notes);
sprintf(s+1,"%d",chord_no);
s[0] = strlen(s+1);
get_item_by_nifty_label(my_complete_window->the_window,
"chord_no",1,decoder_ptr,&hh);
if (VALID_HANDLE(hh)) {
normal_text_style();
SetIText(hh,(unsigned char *) s);
normal_text_style();
}
}
} //-- end if have previous chord
//----- static text ------
normal_text_style();
refresh_text(my_complete_window,"tx1",1,decoder_ptr);
normal_text_style();
if (!ready_to_update) {
SetPort(save_graf);
}
}//---end if need to redraw
}